class Inherits(object):
    """A class whose attribute lookup routine searches a number of parent objects when it fails 
    to find the requested attribute in the object's dictionary or class."""
    def __init__(self, *parents):
        self.__parents = list(parents)
        
    def __getattr__(self, attr):
        try:
            return object.__getattr__(self, attr)
        except AttributeError:
            for parent in self.__parents:
                try:
                    return getattr(parent, attr)
                except Exception:
                    pass
            raise AttributeError("attribute '%s' not found" % (attr,))
            
    def inherit_from(self, *parents):
        self.__parents.extend(parents)
        
    def deinherit_from(self, *parents):
        my_parents = self.__parents
        for parent in parents:
            my_parents.remove(parent)
            
class Reportable(object):
    """This class implements a inspect() method which prints a nicely formatted report consisting 
    of (key, value) pairs returned by the report_items() method (which should be redefined in 
    subclasses)."""
    report_block_lim = "|"
    report_block_sep = "+" + "-" * 20
    report_line_fmt = "%20s: %s"
    
    def inspect(self, display=True):
        report = self.__class__.report(self.report_items(), title=object.__repr__(self))
        if display:
            print report
        else:
            return report
            
    def report_items(self):
        return ()
        
    @classmethod
    def report(cls, items, title=None):
        lines = []
        if title is not None:
            lines.append(str(title))
        if len(items) > 0:
            line_fmt = cls.report_line_fmt
            block_sep = cls.report_block_sep
            block_lim = cls.report_block_lim
            block_ind = block_lim + "   "
            custom_indent = TextProcessor(indent=block_ind).indent
            stack = [(items, 0)]
            while len(stack) > 0:
                block, pos = stack.pop()
                ind = len(stack)
                if pos == 0:
                    lines.append(custom_indent(block_sep, ind))
                while pos < len(block):
                    item = block[pos]
                    if isinstance(item, list):
                        stack.append((block, pos + 1))
                        stack.append((item, 0))
                        break
                    lines.append(custom_indent(block_lim + line_fmt % item, ind))
                    pos += 1
                if pos == len(block):
                    lines.append(custom_indent(block_sep, ind))
        return "\n".join(lines)
        
